package com.hmall.search.service.impl;

import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domin.ItemPageQuery;
import com.hmall.search.domin.po.ItemDoc;
import com.hmall.search.service.ISearchService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @Author mr.wu
 * @Data #{DATE} #{TIME}
 */
@Service
@RequiredArgsConstructor
public class SearchServiceImpl implements ISearchService {

    private final ElasticsearchClient esClient;
    @Override
    public PageDTO<ItemDoc> searchPage(ItemPageQuery query) throws IOException {


        try {
            SearchRequest.Builder builder = new SearchRequest.Builder();

            builder
                    .trackTotalHits(x->x.enabled(true))
                    .query(q -> {
                                q.bool(b -> {
                                            b.must(b1->{
                                                //如果搜索关键字不为空
                                                if (StrUtil.isNotBlank(query.getKey())) {
                                                    b1.multiMatch(m -> m
                                                            .query(query.getKey())
                                                            .fields("name", "brand", "category", "spec"));
                                                } else {
                                                    //查询所有记录
                                                    b1.matchAll(m -> m);
                                                }
                                                return b1;
                                            });
                                            if (StrUtil.isNotBlank(query.getCategory())) {
                                                b.filter(f -> f.term(t -> t.field("category").value(query.getCategory())));
                                            }
                                            //品牌
                                            if (StrUtil.isNotBlank(query.getBrand())) {
                                                b.filter(f -> f.term(t -> t.field("brand").value(query.getBrand())));
                                            }
                                            //价格
                                            if (query.getMinPrice() != null && query.getMaxPrice() != null) {
                                                b.filter(f -> f.range(r -> r.field("price").gte(JsonData.of(query.getMinPrice())).lte(JsonData.of(query.getMaxPrice()))));
                                            }
                                            return b;
                                        }

                                );

                                return q;
                            }
                    )

                    .size(query.getPageSize())
                    .from(query.from());
            //指定索引
            builder.index("items");
            //排序
            if (StrUtil.isNotBlank(query.getSortBy())) {
                builder.sort(sort -> sort.field(f -> f.field(query.getSortBy()).order(query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc)));
            }
            //高亮
            if (StrUtil.isNotBlank(query.getKey())) {
                builder.highlight(h -> h
                        .fields("name", f -> f
                                .preTags("<em>")
                                .postTags("</em>")));
            }
            //构建请求
            SearchRequest build = builder.build();
            //发送请求
            SearchResponse<ItemDoc> response = esClient.search(build, ItemDoc.class);

            //解析响应
            //匹配的总数量
            TotalHits total = response.hits().total();
            //获取结果列表
            List<Hit<ItemDoc>> hits = response.hits().hits();
            //转为List<ItemDoc>
            List<ItemDoc> itemDocs = hits.stream().map(hit -> {
                ItemDoc source = hit.source();
                //解析高亮结果
                Map<String, List<String>> highlightFields = hit.highlight();
                if (highlightFields != null) {
                    List<String> name = highlightFields.get("name");
                    if (name != null) {
                        String highlightName = name.get(0);
                        source.setName(highlightName);
                    }
                }
                return source;
            }).collect(Collectors.toList());
            Page<ItemDoc> page = Page.of(query.getPageNo(), query.getPageSize(), total.value());
            PageDTO<ItemDoc> pageDTO = PageDTO.of(page);
            pageDTO.setList(itemDocs);
            return pageDTO;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<String> suggestion(String key) throws IOException {
        System.out.println(key);
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index("items")
                .suggest(s->s.text(key).suggesters("suggestion_suggest",
                        su->su.completion(c->c.field("suggestion").size(100).skipDuplicates(true
                        ))));
        SearchRequest request = builder.build();
        SearchResponse<ItemDoc> response = esClient.search(request, ItemDoc.class);
        List<String> list  =new ArrayList<>();
        response.suggest().get("suggestion_suggest").forEach(b->{
            b.completion().options().forEach(c->{
                list.add(c.text());
            });
        });

        return list;
    }

}
